#ifndef REF_TABLE_H
#define REF_TABLE_H

#include <list>
#include <vector>
#include "Logger.h"

template <class T>
class RefTable
{
private:
	static const int MIN_SIZE = 1024;

	std::vector<T*> _slots;
	std::vector<int> _emptySlots;

	void expand()
	{
		// Doubles size of vector to hold more elements
		int oldSize = _slots.size();
		_slots.resize( 2*oldSize );
		int newSize = _slots.size();

		// Add new elements as empty slots
		for (int i = oldSize; i < newSize; ++i)
		{
			_emptySlots.push_back(i);
		}
	}

public:
	RefTable()
	{
		// Create a minimum size storage array
		_slots.resize(MIN_SIZE);

		// Add all indices of this array as free slots
		for (int i = 0; i < MIN_SIZE; ++i)
		{
			_emptySlots.push_back(i);
		}
	}

	inline T *operator[] (int idx)
	{
		// Check bounds, return null on failure
		if (idx < 0 || (unsigned int)idx >= _slots.size())
		{
			return NULL;
		}

		// Otherwise, return object from array
		return _slots[idx];
	}

	inline int nextFreeSlot()
	{
		if (_emptySlots.empty())
		{
			expand();
		}

		// Get next available slot
		int idx = _emptySlots.back();
		return idx;
	}

	inline int add(T *value)
	{
		// Check for available slots
		if (_emptySlots.empty())
		{
			expand();
		}

		// Get next available slot
		int idx = _emptySlots.back();
		_emptySlots.pop_back();

		// Store the object in the next available slot
		_slots[idx] = value;
		return idx;
	}

	inline void remove(int idx)
	{
		// Check bounds, return on failure
		if (idx < 0 || (unsigned int)idx >= _slots.size())
		{
			return;
		}

		// Clear out that slot from the vector
		_slots[idx] = NULL;
		_emptySlots.push_back(idx);
	}

	inline int size()
	{
		return _slots.size() - _emptySlots.size();
	}

	inline int capacity()
	{
		return _slots.size();
	}
};

#endif
